package com.example.chatservice.service.impl;


import com.example.chatdbservice.mapper.ChatSessionMapper;
import com.example.chatservice.mapper.ChatMessageMapper;
import com.example.chatservice.service.ChatMessageService;
import com.example.chatservice.webSocket.MessageHandler;
import com.example.chatservice.webSocket.MessagePublisher;
import com.example.userservice.mapper.UserContactMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.example.config.redis.RedisComponent;
import org.example.entity.config.AppConfig;
import org.example.entity.constants.Constants;
import org.example.entity.dto.MessageSendDto;
import org.example.entity.dto.SysSettingDto;
import org.example.entity.dto.TokenUserInfoDto;
import org.example.entity.enums.*;
import org.example.entity.po.ChatMessage;
import org.example.entity.po.ChatSession;
import org.example.entity.po.UserContact;
import org.example.entity.query.ChatMessageQuery;
import org.example.entity.query.ChatSessionQuery;
import org.example.entity.query.SimplePage;
import org.example.entity.query.UserContactQuery;
import org.example.entity.vo.PaginationResultVO;
import org.example.exception.BusinessException;
import org.example.utils.CopyTools;
import org.example.utils.DateUtil;
import org.example.utils.StringTools;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;


/**
 * 聊天消息表 业务接口实现
 */
@Service("chatMessageService")
@Slf4j
public class ChatMessageServiceImpl implements ChatMessageService {


    public static final double bytesLimit = 1024*1000;
    @Resource
    private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

    @Resource
    private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

    @Resource
    private AppConfig appConfig;

    @Resource
    private UserContactMapper<UserContact, UserContactQuery> userContactMapper;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private MessageHandler messageHandler;

    @Resource
    private MessagePublisher messagePublisher;
    /**
     * 根据条件查询列表
     */
    @Override
    public List<ChatMessage> findListByParam(ChatMessageQuery param) {
        return this.chatMessageMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(ChatMessageQuery param) {
        return this.chatMessageMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<ChatMessage> findListByPage(ChatMessageQuery param) {
        int count = this.findCountByParam(param);
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<ChatMessage> list = this.findListByParam(param);
        PaginationResultVO<ChatMessage> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(ChatMessage bean) {
        return this.chatMessageMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<ChatMessage> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.chatMessageMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<ChatMessage> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.chatMessageMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(ChatMessage bean, ChatMessageQuery param) {
        StringTools.checkParam(param);
        return this.chatMessageMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(ChatMessageQuery param) {
        StringTools.checkParam(param);
        return this.chatMessageMapper.deleteByParam(param);
    }

    /**
     * 根据MessageId获取对象
     */
    @Override
    public ChatMessage getChatMessageByMessageId(Long messageId) {
        return this.chatMessageMapper.selectByMessageId(messageId);
    }

    /**
     * 根据MessageId修改
     */
    @Override
    public Integer updateChatMessageByMessageId(ChatMessage bean, Long messageId) {
        return this.chatMessageMapper.updateByMessageId(bean, messageId);
    }

    /**
     * 根据MessageId删除
     */
    @Override
    public Integer deleteChatMessageByMessageId(Long messageId) {
        return this.chatMessageMapper.deleteByMessageId(messageId);
    }


    @Override
    public MessageSendDto saveMessage(ChatMessage chatMessage, TokenUserInfoDto tokenUserInfoDto) {
        //不是机器人回复，判断好友状态
        if (!Constants.ROBOT_UID.equals(tokenUserInfoDto.getUserId())){
            List<String> myContact = redisComponent.getMyContact(tokenUserInfoDto.getUserId());
            if (!myContact.contains(chatMessage.getContactId())){
                UserContactTypeEnum contactTypeEnum = UserContactTypeEnum.getByPrefix(chatMessage.getContactId());
                if (UserContactTypeEnum.USER == contactTypeEnum){
                    throw new BusinessException(ResponseCodeEnum.CODE_902);
                }else {
                    throw new BusinessException(ResponseCodeEnum.CODE_903);
                }
            }
        }
        String sessionId = null;
        if (UserContactTypeEnum.USER.getType().equals(UserContactTypeEnum.getByPrefix(chatMessage.getContactId()).getType())){
            sessionId = StringTools.getChatSessionId4User(new String[]{chatMessage.getContactId(),tokenUserInfoDto.getUserId()});
        }else {
            sessionId = StringTools.getChatSessionId4Group(chatMessage.getContactId());
        }
        Long curTime = System.currentTimeMillis();
        Integer status = MessageTypeEnum.MEDIA_CHAT.getType() == chatMessage.getMessageType()? MessageStatusEnum.SENDING.getStatus() : MessageStatusEnum.SENDED.getStatus();
        String messageContent = StringTools.cleanHtmlTag(chatMessage.getMessageContent());


        chatMessage.setSessionId(sessionId);
        chatMessage.setStatus(status);
        chatMessage.setSendTime(curTime);
        chatMessage.setMessageContent(messageContent);
        chatMessage.setSendUserId(tokenUserInfoDto.getUserId());
        chatMessage.setSendUserNickName(tokenUserInfoDto.getNickName());
        chatMessage.setContactType(UserContactTypeEnum.getByPrefix(chatMessage.getContactId()).getType());

        chatMessageMapper.insert(chatMessage);
        //更新会话
        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(messageContent);
        if (UserContactTypeEnum.GROUP == UserContactTypeEnum.getByPrefix(chatMessage.getContactId())){
            chatSession.setLastMessage(tokenUserInfoDto.getNickName() + ":" + messageContent);
        }
        chatSession.setLastReceiveTime(curTime);
        chatSessionMapper.updateBySessionId(chatSession,sessionId);

        MessageSendDto messageSendDto = CopyTools.copy(chatMessage, MessageSendDto.class);
        if (Constants.ROBOT_UID.equals(chatMessage.getContactId())){
            SysSettingDto sysSettingDto = redisComponent.getSysSetting();
            TokenUserInfoDto dto = new TokenUserInfoDto();
            dto.setUserId(sysSettingDto.getRobotUid());
            dto.setNickName(sysSettingDto.getRobotNickName());
            ChatMessage robotchatMessage = new ChatMessage();
            robotchatMessage.setContactId(tokenUserInfoDto.getUserId());
            robotchatMessage.setMessageContent("我是机器人，回你妈滚");
            robotchatMessage.setMessageType(MessageTypeEnum.CHAT.getType());
            saveMessage(robotchatMessage,dto);
        }else {
//            messageHandler.sendMessage(messageSendDto);
            messagePublisher.sendMsg(messageSendDto);
        }
        return messageSendDto;
    }

    @Override
    public void uploadFile(Long messageId, MultipartFile file, MultipartFile cover, TokenUserInfoDto tokenUserInfo) {
        ChatMessage chatMessage = chatMessageMapper.selectByMessageId(messageId);
        if (chatMessage == null){
            throw new BusinessException("发送失败");
        }
        if (!chatMessage.getSendUserId().equals(tokenUserInfo.getUserId())){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        SysSettingDto sysSetting = redisComponent.getSysSetting();
        String fileSuffix = StringTools.getFileSuffix(file.getOriginalFilename());
        if (!fileSuffix.isEmpty()
                && ArrayUtils.contains(Constants.IMAGE_SUFFIX_LIST,fileSuffix.toLowerCase())
                && file.getSize() > sysSetting.getMaxImageSize() * Constants.FILE_SIZE_MB){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }else if (!fileSuffix.isEmpty()
                && ArrayUtils.contains(Constants.VIDEO_SUFFIX_LIST,fileSuffix.toLowerCase())
                && file.getSize() > sysSetting.getMaxVideoSize() * Constants.FILE_SIZE_MB){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }else if (file.getSize() > sysSetting.getMaxFileSize() * Constants.FILE_SIZE_MB){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        String fileRealName = messageId + fileSuffix;
        String month = DateUtil.format(new Date(chatMessage.getSendTime()),"YYYY-MM");
        File fileFolder = new File(appConfig.getProjectFolder()  + Constants.FILE_FOLDER_FILE +month);
        if (!fileFolder.exists()){
            fileFolder.mkdirs();
        }
        try {
            file.transferTo(new File(fileFolder.getPath() +"/"+ fileRealName));
            if (cover != null) {
                cover.transferTo(new File(fileFolder.getPath() + "/" + fileRealName + Constants.COVER_IMAGE_SUFFIX));
            }
        } catch (IOException e) {
            log.error("文件存储出错",e);
            throw new BusinessException("文件上传失败");
        }

        ChatMessage updateInfo = new ChatMessage();
        updateInfo.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessageMapper.updateByMessageId(updateInfo,messageId);

        MessageSendDto messageSendDto = new MessageSendDto();
        messageSendDto.setStatus(MessageStatusEnum.SENDED.getStatus());
        messageSendDto.setMessageId(messageId);
        messageSendDto.setContactId(chatMessage.getContactId());
        messageSendDto.setMessageType(MessageTypeEnum.FILE_UPLOAD.getType());
//        messageHandler.sendMessage(messageSendDto);
        messagePublisher.sendMsg(messageSendDto);
    }

    @Override
    public File downloadFile(TokenUserInfoDto userInfoDto, Long messageId, Boolean cover) {
        ChatMessage message = chatMessageMapper.selectByMessageId(messageId);
        String contactId = message.getContactId();
        UserContactTypeEnum contactTypeEnum = UserContactTypeEnum.getByPrefix(contactId);
        if (UserContactTypeEnum.USER.getType().equals(contactTypeEnum) && !userInfoDto.getUserId().equals(message.getContactId())) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        if (UserContactTypeEnum.GROUP.getType().equals(contactTypeEnum)) {
            UserContactQuery userContactQuery = new UserContactQuery();
            userContactQuery.setUserId(userInfoDto.getUserId());
            userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());
            userContactQuery.setContactId(contactId);
            userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
            Integer contactCount = userContactMapper.selectCount(userContactQuery);
            if (contactCount == 0) {
                throw new BusinessException(ResponseCodeEnum.CODE_600);
            }
        }
        String month = DateUtil.format(new Date(message.getSendTime()), "YYYY-MM");
        File folder = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + month);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String fileName = message.getFileName();
        String fileExtName = StringTools.getFileSuffix(fileName);
        String fileRealName = messageId + fileExtName;

        if (cover != null && cover) {
            fileRealName = fileRealName + Constants.COVER_IMAGE_SUFFIX;
        }
        File file = new File(folder.getPath() + "/" + fileRealName);
        if (!file.exists()) {
            log.info("文件不存在");
            throw new BusinessException(ResponseCodeEnum.CODE_602);
        }
        return file;
    }
}